Матч 241, Путешествие по воздуху (AirTravel)

Дивизион 2, Уровень 3

 

На планете, имеющей форму шара с радиусом 4000, задано множество аэропортов. Координаты i - го аэропорта задаются парой (широта, долгота) = (latitude[i], longitude[i]), заданных в градусах. В ячейке canTravel[i] содержатся номера аэропортов, в которые можно вылетать из i - го. Если существует путь из i - го аэропорта в j - ый, то необязательно существует путь из j - го в i - ый.

Из аэропорта с номером origin необходимо доставить груз в аэропорт с номером destination, пролетев наименьшее расстояние. Нумерация аэропортов начинается с 0.

Расстояние от точки (lat1, lon1) до (lat2, lon2) на шаре радиуса radius равно

radius * acos(sin(lat1) * sin(lat2) +

cos(lat1) * cos(lat2) * cos(lon1 - lon2))

 

Класс: AirTravel

Метод: double shortestTrip(vector<int> latitude,

         vector<int> longitude,

         vector<string> canTravel, int origin, int destination)

Ограничения: latitude,  longitude и longitude содержат от 1 до 20 элементов, -89 £ latitude[i] £ 89, -179 £ longitude[i] £ 179, canTravel[i] является строкой, содержащей числа от 0 до n – 1, где n – количество элементов в latitude, 0 £ origin, destination £ n – 1, никакие два аэропорта не имеют одинаковых координат.

 

Вход. Массивы latitude и longitude содержат координаты (широту и долготу) аэропортов.

 

Выход. Наименьшее расстояние, которое следует преодолеть для перелета из аэропорта origin в destination.

 

Пример входа

latitude

longitude

canTravel

origin

destination

{0, 0, 70}

{90, 0, 45}

{"2", "0 2", "0 1"}

0

1

{0, 0, 70}

{90, 0, 45}

{"1 2", "0 2", "0 1"}

0

1

{0, 20, 55}

{-20, 85, 42}

{"1", "0", "0"}

0

2

 

Пример выхода

10612.237799994255

6283.185307179586

-1.0

 

 

РЕШЕНИЕ

алгоритм Дейкстры + геометрия

 

Заполним матрицу расстояний m, положив m[i][j] равным расстоянию между i - ым и j - ым аэропортом, если путь между ними существует, и +¥ иначе. Расстояние между аэропортами вычисляем по формуле, приведенной в условии. Поскольку широта и долгота заданы в градусах, при вычислении тригонометрических функций следует переводить их в радианы.

При помощи алгоритма Дейкстры ищем кратчайший путь от аэропорта origin до destination. Если по окончании работы алгоритма Дейкстры d[destination] содержит +¥, то возвращаем -1 (требуемого пути не существует).

 

ПРОГРАММА

 

#include <cstdio>

#include <string>

#include <vector>

#include <sstream>

#include <cmath>

#define MAX 21

#define INF 2100000000

#define K acos(-1.0) / 180.0

using namespace std;

 

double m[MAX][MAX], d[MAX];

int used[MAX], n;

 

void Init(int origin)

{

  int i, j;

  for(i = 0; i < n; i++)

  {

    for(j = 0; j < n; j++)

      m[i][j] = INF / 2;

    d[i] = INF / 2;

  }

  memset(used,0,sizeof(used));

  d[origin] = 0;

}

 

void Relax(int i, int j)

{

  if (d[j] > d[i] + m[i][j]) d[j] = d[i] + m[i][j];

}

 

int Find_Min(void)

{

  int i, v;

  double min = INF / 2;

  for(i = 0; i < n; i++)

    if (!used[i] && d[i] < min) min = d[i], v = i;

  return v;

}

 

double Dist(double lat1, double lon1, double lat2, double lon2)

{

  return 4000.0 * acos(sin(K * lat1) * sin(K * lat2) + cos(K * lat1) *

         cos(K * lat2) * cos(K*lon1 - K*lon2));

}

 

class AirTravel

{

public:

  double shortestTrip(vector<int> latitude, vector<int> longitude,

                      vector<string> canTravel, int origin, int destination)

  {

    int i, j, v;

    n = latitude.size(); Init(origin);

    for(i = 0; i < canTravel.size(); i++)

    {

      stringstream in(canTravel[i]);

      while(in >> j)

        m[i][j] = Dist(latitude[i],longitude[i],latitude[j],longitude[j]);

    }

    for(i = 0; i < n; i++)

    {

      v = Find_Min();

      for(j = 0; j < n; j++)

        if (!used[j]) Relax(v,j);

      used[v] = 1;

    }

    return (d[destination] > INF / 3) ? -1 : d[destination];

  }

};